/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司 All rights reserved.
 */
package cn.net.ecode.common.config;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.core.io.DefaultResourceLoader;

import cn.net.ecode.common.datasource.DataSourceHolder;
import cn.net.ecode.common.persistence.DataEntity;
import cn.net.ecode.common.utils.FileUtils;
import cn.net.ecode.common.utils.PropertiesLoader;
import cn.net.ecode.common.utils.StringUtils;
import cn.net.ecode.common.web.Servlets;
import cn.net.ecode.modules.sys.utils.ConfigUtils;

import com.google.common.collect.Maps;

/**
 * 全局配置类
 * @author ThinkGem
 * @version 2013-03-23
 */
public class Global {
	
	/**
	 * 当前对象实例
	 */
	private static Global global = new Global();

	/**
	 * 保存全局属性值
	 */
	private static Map<String, String> map = Maps.newHashMap();
	
	/**
	 * 显示/隐藏
	 */
	public static final String SHOW = "1";
	public static final String HIDE = "0";

	/**
	 * 是/否
	 */
	public static final String YES = "1";
	public static final String NO = "0";

	/**
	 * 对/错
	 */
	public static final String TRUE = "true";
	public static final String FALSE = "false";
	
	/**
	 * 上传文件基础虚拟路径
	 */
	public static final String USERFILES_BASE_URL = "/userfiles/";
	
	/**
	 * 获取当前对象实例（主要是方便在Mybatis的Mapper中调用）
	 */
	public static Global getInstance() {
		return global;
	}
	
	/**
	 * JSP页面中获取常量用： @see ${fns:getConst('YES')}
	 * @param field 字段名，为 “Global.Fields”时返回所有字段的js对象。
	 */
	public static Object getConst(String field) {
		try {
			if ("Global.Fields".equals(field)){
				String value = map.get("__" + field);
				if (value == null){
					StringBuilder fields = new StringBuilder();
					for (Field f : Global.class.getFields()){
						fields.append(f.getName() + ":'" + f.get(null)+"', ");
					}
					for (Field f : DataEntity.class.getFields()){
						fields.append(f.getName() + ":'" + f.get(null)+"', ");
					}
					int length = fields.length();
					value = length > 2 ? fields.substring(0, length - 2) : "";
					map.put("__" + field, value);
				}
				return value;
			}
			Object value = Global.class.getField(field).get(null);
			if (value == null){
				value = DataEntity.class.getField(field).get(null);
			}
			return value;
		} catch (Exception e) {
			// 异常代表无配置，这里什么也不做
		}
		return null;
	}
	
	/**
	 * 获取配置（先从System.getProperty获取，取不到读取app.properties中的值，
	 *          如果还取不到，则获取sys_config表中的值），仍然获取不到，返回空字符串
	 * @see ${fns:getConfig('adminPath')}
	 * @return 获取不到，返回空字符串
	 */
	public static String getConfig(String key) {
		String value = map.get(key);
		if (value == null){
			try{
				// 读取系统属性及配置文件中的属性
				value = PropertiesLoader.getInstance().getProperty(key);
				// 支持  ${fns:getConfig('key')} 嵌套取值的问题. example: key=${xx}/yy
				Pattern p = Pattern.compile("\\$\\{.*?\\}");
		    	Matcher m = p.matcher(value);
		        while(m.find()) {
		            String g = m.group();
		            String keyChild = g.replaceAll("\\$\\{", "").replaceAll("\\}", "");
		            value = value.replace(g, getConfig(keyChild));
		        }
				map.put(key, value);
			}catch(NoSuchElementException e){
				// 读取系统参数表（sys_config）中的值
				value = ConfigUtils.getConfig(key).getValue();
				if (value != null){
					// 指定参数值是从系统参数表中读取的
					map.put(key, "read_sys_config_table");
					return value;
				}else{
					// 仍然获取不到，返回空字符串
					value = StringUtils.EMPTY;
					map.put(key, value);
				}
			}
		}
		// 如果值来自于系统参数表，则从系统参数表中读取
		if ("read_sys_config_table".equals(value)){
			value = ConfigUtils.getConfig(key).getValue();
		}
		return value;
	}

	/**
	 * 获取配置（先从System.getProperty获取，取不到读取app.properties中的值，
	 *          如果还取不到，则获取sys_config表中的值），仍然获取不到，返回空。
	 * @see ${fns:getConfig('adminPath')}
	 * @return 获取不到，返回defValue默认值
	 */
	public static String getConfig(String key, String defValue) {
		String value = getConfig(key);
		return StringUtils.isBlank(value) ? defValue : value;
	}
	
	/**
	 * 获取配置（先从System.getProperty获取，取不到读取app.properties中的值，
	 * 			不再读取sys_config表的值），获取不到，返回空。
	 * @return 获取不到，返回空
	 */
	public static String getProperty(String key) {
		String value = map.get(key);
		if (value == null){
			try{
				// 读取系统属性及配置文件中的属性
				value = PropertiesLoader.getInstance().getProperty(key);
				// 支持  Global.getProperty('key') 嵌套取值的问题. example: key=${xx}/yy
				Pattern p = Pattern.compile("\\$\\{.*?\\}");
		    	Matcher m = p.matcher(value);
		        while(m.find()) {
		            String g = m.group();
		            String keyChild = g.replaceAll("\\$\\{", "").replaceAll("\\}", "");
		            value = value.replace(g, getProperty(keyChild));
		        }
				map.put(key, value);
			}catch(NoSuchElementException e){
				// 找不到属性，则忽略异常。
			}
		}
		return value;
	}
	
	/**
	 * 获取配置（先从System.getProperty获取，取不到读取app.properties中的值，
	 * 			不再读取sys_config表的值），获取不到，返回空。
	 * @return 获取不到，返回空defValue默认值
	 */
	public static String getProperty(String key, String defValue) {
		String value = getProperty(key);
		return StringUtils.isBlank(value) ? defValue : value;
	}
	
	/**
	 * 获取管理端根路径
	 */
	public static String getAdminPath() {
		return getConfig("adminPath");
	}
	
	/**
	 * 获取前端根路径
	 */
	public static String getFrontPath() {
		return getConfig("frontPath");
	}
	
	/**
	 * 获取URL后缀
	 */
	public static String getUrlSuffix() {
		return getConfig("urlSuffix");
	}
	
	/**
	 * 获取当前数据库连接信息
	 * @param key 参数名（type、driver、url、username）
	 * @return 数据库连接信息
	 */
	public static String getJdbcInfo(String key){
		String dsn = DataSourceHolder.getDataSourceName();
		String jdbcKey = "jdbc" + (dsn == null ? "" : "." + dsn) + "." + key;
		String value = getConfig(jdbcKey);
		if (StringUtils.isBlank(value)){
			throw new RuntimeException("properties 文件中缺少 " + jdbcKey + " 数据源参数配置.");
		}
		return value;
	}
	
	/**
	 * 获取数据库类型
	 * @return oracle、mysql、mssql、h2、db2、hsql、postgre、sybase
	 */
	public static String getJdbcType(){
		String value = getJdbcInfo("type");
		return value;
	}
	
	/**
	 * 获取当前数据库名称(如果数据库类型为highgo，则自动转化为oracle数据库)
	 * @return oracle(highgo)、mysql、mssql、h2、db2、hsql、postgre、sybase
	 */
	public static String getDbName(){
		String value = getJdbcInfo("type");
		return "highgo".equals(value)?"oracle":value;
	}
	
	/**
	 * 是否是演示模式，演示模式下不能修改用户、角色、密码、菜单、授权
	 */
	public static Boolean isDemoMode() {
		String dm = getConfig("demoMode");
		return "true".equals(dm) || "1".equals(dm);
	}
	
	/**
	 * 在修改系统用户和角色时是否同步到Activiti
	 */
	public static Boolean isSynActivitiIndetity() {
		String dm = getConfig("activiti.isSynActivitiIndetity");
		return "true".equals(dm) || "1".equals(dm);
	}
	
	/**
	 * 获取上传文件的根目录
	 * @return
	 */
	public static String getUserfilesBaseDir() {
		String dir = getConfig("userfiles.basedir");
		if (StringUtils.isBlank(dir)){
			try {
				dir = Servlets.getRequest().getSession().getServletContext().getRealPath("/");
			} catch (Exception e) {
				return "";
			}
		}
		if(!dir.endsWith("/")) {
			dir += "/";
		}
//		System.out.println("userfiles.basedir: " + dir);
		return dir;
	}
	
	/**
	 * 获取上传文件的根目录
	 * @param path 相对的路径 
	 * @return
	 */
	public static String getUserfilesBaseDir(String path) {
		return FileUtils.path(getUserfilesBaseDir() + USERFILES_BASE_URL + path);
	}
	
//	/**
//	 * 在修改系统用户和角色时是否同步到Activiti
//	 */
//	public static Boolean isSynActivitiIndetity() {
//		String dm = getConfig("activiti.isSynActivitiIndetity");
//		return "true".equals(dm) || "1".equals(dm);
//	}

    /**
     * 获取工程路径
     * @return
     */
    public static String getProjectPath(){
		String projectPath = "";
		try {
			File file = new DefaultResourceLoader().getResource("").getFile();
			if (file != null){
				while(true){
					File f = new File(file.getPath() + File.separator + "src" + File.separator + "main");
					if (f == null || f.exists()){
						break;
					}
					if (file.getParentFile() != null){
						file = file.getParentFile();
					}else{
						break;
					}
				}
				projectPath = file.toString();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return projectPath;
    }

	/**
	 * 是否使用集团用户模式
	 */
	public static Boolean isUseCorpModel(){
		return Global.TRUE.equals(Global.getConfig("user.useCorpModel"));
	}
	
}
